package com.example.terminalservice.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.example.terminalservice.common.CodeEnum;
import com.example.terminalservice.common.Constants;
import com.example.terminalservice.common.Result;
import com.example.terminalservice.exception.MyException;
import com.example.terminalservice.pojo.User;
import com.example.terminalservice.pojo.dto.LoginDTO;
import com.example.terminalservice.pojo.dto.PwdDTO;
import com.example.terminalservice.pojo.dto.RegisterDTO;
import com.example.terminalservice.pojo.dto.UserInfoDTO;
import com.example.terminalservice.service.UserService;
import com.example.terminalservice.utils.EmailUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.util.Date;
import java.util.List;

/**
 * @author 28142
 * @description UserController
 * @date 2023/8/4 16:35
 */
@RestController
@RequestMapping("/user")
@Api(tags = "用户管理")
@Validated
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private EmailUtils emailUtils;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 获取登录验证码
     * @author 杨雨盛
     * @date 2023/8/4 17:42
     */
    @ApiOperation("获取登录验证码")
    @GetMapping("/login/code")
    public Result getLoginCode(HttpServletRequest request) {
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100, 4, 20);
        // lineCaptcha.write(System.getProperty("user.dir") + "\\code.jpg");
        lineCaptcha.write("E:\\project\\datasource\\vue\\src\\assets\\code.jpg");
        // 将验证码存入session，使用jwt无状态认证，禁用session
        // request.getSession().setAttribute("code", lineCaptcha.getCode());
        // 生成一个uuid作为key存储验证码
        String key = IdUtil.simpleUUID();
        stringRedisTemplate.opsForValue().set(key, lineCaptcha.getCode());
        return Result.success(key);
    }

    /**
     * 注册
     * @author 杨雨盛
     * @date 2023/8/5 9:10
     * @param registerDTO
     * @return com.example.terminalservice.common.Result
     */
    @ApiOperation("注册")
    @PostMapping("/register")
    public Result register(@RequestBody @Valid RegisterDTO registerDTO) {
        return userService.register(registerDTO) ? Result.success(CodeEnum.CODE_200.getCode(), "注册成功", null) : Result.error();
    }

    /**
     * 发送邮件，生成注册验证码
     * @author 杨雨盛
     * @date 2023/8/5 9:10
     * @param email
     * @return com.example.terminalservice.common.Result
     */
    @ApiOperation("发送邮件，生成注册验证码")
    @GetMapping("/register/code")
    public Result sendRegisterCode(@NotBlank(message = "邮箱不能为空")
                                   @Email(message = "请输入一个合法邮箱")
                                   @RequestParam String email) {
        // 从redis缓存中读取验证码发送时间，如果超过一分钟，则可以继续发送
        String code = stringRedisTemplate.opsForValue().get(email);
        if (StrUtil.isBlank(stringRedisTemplate.opsForValue().get(email + code))) {
            emailUtils.sendEmail(email);
        } else {
            throw new MyException(CodeEnum.CODE_403.getCode(), "请不要重复发送验证码");
        }
        return Result.success();
    }

    /**
     * 分页条件查询用户列表
     * @author 杨雨盛
     * @date 2023/8/6 16:49
     * @param pageNum
     * @param pageSize
     * @param username
     * @return com.example.terminalservice.common.Result
     */
    @ApiOperation("分页条件查询用户列表")
    @GetMapping("/{pageNum}/{pageSize}")
    @PreAuthorize("hasAnyAuthority('sys:user')")
    public Result findPage(@PathVariable Integer pageNum,
                           @PathVariable Integer pageSize,
                           @RequestParam(required = false) String username) {
        return userService.findPage(pageNum, pageSize, username);
    }

    /**
     * 添加或修改用户
     * @author 杨雨盛
     * @date 2023/8/6 18:43
     * @param user
     * @return com.example.terminalservice.common.Result
     */
    @ApiOperation("添加或修改用户")
    @PostMapping
    @PreAuthorize("hasAnyAuthority('sys:user:add', 'sys:user:update')")
    public Result saveUser(@RequestBody User user) {
        return userService.saveUser(user) ? Result.success() : Result.error();
    }

    /**
     * 重置密码，初始密码123456
     * @author 杨雨盛
     * @date 2023/8/6 18:53
     * @param id
     * @return com.example.terminalservice.common.Result
     */
    @ApiOperation("重置密码")
    @PostMapping("/reset/{id}")
    @PreAuthorize("hasAnyAuthority('sys:user:resetPwd')")
    public Result reset(@PathVariable Integer id) {
        User user = new User();
        user.setId(id);
        user.setPassword(passwordEncoder.encode(Constants.INIT_PWD));
        user.setUpdateTime(new Date());
        return userService.updateById(user) ? Result.success() : Result.error();
    }

    /**
     * 上传头像
     * @author 杨雨盛
     * @date 2023/8/11 10:38
     * @param file
     * @param request
     * @return com.example.terminalservice.common.Result
     */
    @ApiOperation("上传头像")
    @PostMapping("/avatar")
    public Result uploadAvatar(@RequestParam("file") MultipartFile file,
                               HttpServletRequest request) {
        return userService.uploadAvatar(file, request);
    }

    /**
     * 根据id删除用户
     * @author 杨雨盛
     * @date 2023/8/6 19:48
     * @param id
     * @return com.example.terminalservice.common.Result
     */
    @ApiOperation("根据id删除用户")
    @DeleteMapping("/{id}")
    @PreAuthorize("hasAnyAuthority('sys:user:del')")
    public Result delUser(@PathVariable Integer id) {
        return userService.removeById(id) ? Result.success() : Result.error();
    }

    /**
     * 批量删除
     * @author 杨雨盛
     * @date 2023/8/6 19:52
     * @param ids
     * @return com.example.terminalservice.common.Result
     */
    @ApiOperation("批量删除")
    @PostMapping("/del/batch")
    @PreAuthorize("hasAnyAuthority('sys:user:del')")
    public Result delBatch(@RequestBody List<Integer> ids) {
        return userService.removeBatchByIds(ids) ? Result.success() : Result.error();
    }

    /**
     * 修改密码
     * @author 杨雨盛
     * @date 2023/8/6 20:12
     * @param pwdDTO
     * @return com.example.terminalservice.common.Result
     */
    @ApiOperation("修改密码")
    @PostMapping("/changePwd")
    public Result changePwd(@RequestBody @Valid PwdDTO pwdDTO) {
        return userService.changePwd(pwdDTO) ? Result.success() : Result.error();
    }

    /**
     * 修改个人信息
     * @author 杨雨盛
     * @date 2023/8/14 14:45
     * @param id
     * @param userInfoDTO
     * @return com.example.terminalservice.common.Result
     */
    @ApiOperation("修改个人信息")
    @PostMapping("/info/{id}")
    public Result changeInfo(@PathVariable Integer id,
                             @RequestBody @Valid UserInfoDTO userInfoDTO) {
        User originalUser = userService.getById(id);
        if (originalUser == null) {
            throw new MyException(CodeEnum.CODE_600.getCode(), "用户不存在");
        }
        // 如果用户修改了用户名，并且改用户名在数据库中已存在，抛异常
        if (!originalUser.getUsername().equals(userInfoDTO.getUsername())) {
            if (userService.getUserByUsername(userInfoDTO.getUsername()) != null) {
                throw new MyException(CodeEnum.CODE_401.getCode(), "用户名已存在");
            }
        }
        User user = new User();
        BeanUtil.copyProperties(userInfoDTO, user);
        user.setId(id);
        user.setUpdateTime(new Date());
        return userService.updateById(user) ? Result.success() : Result.error();
    }
}
